using System.Collections.Generic;
using System.Linq;


namespace RayDen.Library.Core
{
    public class Distribution2D
    {
        List<Distribution1D> pConditionalV;
        Distribution1D pMarginal;

        Distribution2D(float[] data, int nu, int nv)
        {
            this.pConditionalV = new List<Distribution1D>(nv);
            var dataList = data.ToList();
            for(int v = 0; v < nv; ++v)
            {
                // Compute conditional sampling distribution for $\tilde{v}$
                this.pConditionalV.Add(new Distribution1D(dataList.GetRange(v * nu, nu).ToArray()));
            }

            // Compute marginal sampling distribution $p[\tilde{v}]$
            var marginalFunc = new List<float>();
            for(int v = 0; v < nv; ++v)
                marginalFunc.Add(this.pConditionalV[v].funcInt);

            this.pMarginal = new Distribution1D(marginalFunc.ToArray());
        }

        public void SampleContinuous(float u0, float u1, float[] uv, out float pdf)
        {
            float[] pdfs = new float[2];
            int v, vtt;
            uv[1] = this.pMarginal.SampleContinuous(u1, out pdfs[1], out v);
            uv[0] = this.pConditionalV[v].SampleContinuous(u0, out pdfs[0], out vtt);
            pdf = pdfs[0] * pdfs[1];
        }

        public float Pdf(float u, float v)
        {
            int iu = MathLab.Clamp(MathLab.Float2Int(u * this.pConditionalV[0].count), 0, this.pConditionalV[0].count-1);
            int iv = MathLab.Clamp(MathLab.Float2Int(v * this.pMarginal.count), 0, this.pMarginal.count-1);
            if(this.pConditionalV[iv].funcInt * this.pMarginal.funcInt == 0f)
                return 0f;
            return (this.pConditionalV[iv].func[iu] * this.pMarginal.func[iv]) / (this.pConditionalV[iv].funcInt *  this.pMarginal.funcInt);
        }
    }
}